﻿#include"snake.h"
#define POS_X 40
#define POS_Y 15
#define PRESS(VK) ((GetAsyncKeyState(VK)&0x1)?1:0)
void WelcometoGame()
{
	SetPos(90, 25);
	wprintf(L"欢迎来到贪吃蛇");
	SetPos(90, 30);
	system("pause");
	system("cls");
	SetPos(80, 25);
	wprintf(L"按↑.↓.←.→控制方向，按F3加速，按F4减速\n");
	SetPos(88, 28);
	wprintf(L"加速可以获得更高的分数\n");
	SetPos(91, 35);
	system("pause");
	system("cls");
}
void SetPos(short x, short y)
{
	HANDLE houtput = NULL;
	houtput = GetStdHandle(STD_OUTPUT_HANDLE);
	COORD pos = { x,y };
	SetConsoleCursorPosition(houtput, pos);
}
void words()
{
	SetPos(130, 15);
	printf("得分:");
	SetPos(140, 15);
	printf("每个食物得分：");
	SetPos(135, 17);
	printf("作者记录：940");
	SetPos(130, 20);
	printf("不能撞墙，不能自己撞自己");
	SetPos(130, 22);
	printf("按↑.↓.←.→控制方向，按F3加速，按F4减速\n");
	SetPos(130, 23);
	printf("按space暂停游戏，按ESC退出游戏");
	SetPos(130, 25);
	printf("按F5开启超极限速度，在超极限速度下会持续得分");
	SetPos(130, 26);
	printf("按F6关闭超极限速度");
	SetPos(130, 31);
	printf("CSDN <但凡. 出品");
}
void Game(pSnake sn)
{
	int i = 0;
	//上
	for (i = 0;i < 114;i+=2)
	{
		SetPos(i,0);
		wprintf(L"%lc", L'□');
	}
	//下
	
	for (i = 0;i < 114;i+=2)
	{
		SetPos(i, 52);
		wprintf(L"%lc", L'□');
	}
	//左
	for (i = 1;i <= 51;i++)
	{
		SetPos(0, i);
		wprintf(L"%lc", L'□');
	}
	//右
	for (i = 0;i <=51;i++)
	{
		SetPos(112, i);
		wprintf(L"%lc", L'□');
	}
}
//初始化蛇蛇
void initSnake(pSnake sn)
{
	pSnakeNode cur = NULL;//注意cur的类型
	for (int i = 0;i < 5;i++)
	{
		cur = (pSnakeNode)malloc(sizeof(SnakeNode));
		if (cur == NULL)
		{
			perror("initSnake()::malloc()");
			return;
		}
		cur->next = NULL;
		cur->x = POS_X+2*i;
		cur->y=POS_Y;
		if (sn->ps == NULL)
		{
			sn->ps = cur;//如果没有头，就让这个节点当头
		}
		else//头插法***
		{
			cur->next = sn->ps;//指向头
			sn->ps = cur;//让cur成为新的头***
		}
		//咱们创建完了不能free，不然不白连了吗
	}
	//打印蛇蛇
	pSnakeNode pcur = sn->ps;
	while (pcur!= NULL)
	{
		SetPos(pcur->x, pcur->y);
		wprintf(L"%lc", L'●');
		pcur = pcur->next;
	}
	sn->score = 0;
	sn->dir = RIGHT;
	sn->Foodscore = 10;
	sn->Sleeptime = 200;
	sn->state = OK;
}
//创建食物
void CreatFood(pSnake ps)
{
	int x = 0;
	int y = 0;
again:
	//产⽣的x坐标应该是2的倍数，这样才可能和蛇头坐标对⻬。 
	do
	{
		x = rand() % 53 + 2;
		y = rand() % 25 + 1;
	} while (x % 2 != 0);
	pSnakeNode cur = ps->ps;//获取指向蛇头的指针 
	//⻝物不能和蛇⾝冲突 
	while (cur)
	{
		if (cur->x == x && cur->y == y)
		{
			goto again;
		}
		cur = cur->next;
	}
	pSnakeNode pFood = (pSnakeNode)malloc(sizeof(SnakeNode)); //创建⻝物 
	if (pFood == NULL)
	{
		perror("CreateFood::malloc()");
		return;
	}
	else
	{
		pFood->x = x;
		pFood->y = y;
		SetPos(pFood->x, pFood->y);
		wprintf(L"%c", L'★');
		ps->_food = pFood;
	}
}

void Gamestart(pSnake snake)
{
	//设置游戏窗口大小
	system("mode con cols=200 lines=60");
	system("title 贪吃蛇");
	HANDLE houtput = GetStdHandle(STD_OUTPUT_HANDLE);
	//隐藏光标
	CONSOLE_CURSOR_INFO CUR;
	GetConsoleCursorInfo(houtput, &CUR);
	CUR.bVisible = false;
	SetConsoleCursorInfo(houtput, &CUR);
	//打印欢迎界面
	WelcometoGame();
	//打印游戏界面
	Game(snake);
	//初始化蛇蛇
	initSnake(snake);
	//创建食物
	CreatFood(snake);
}
void Pause()
{
	while (1)
	{
		Sleep(1000);
		if (PRESS(VK_SPACE))
		{
			break;
		}
	}
}
void KEY_PRESS(pSnake sn)
{
	if (PRESS(VK_UP) && sn->dir != DOWN)
	{
		sn->dir = UP;
	}
	else if (PRESS(VK_DOWN) && sn->dir != UP)
	{
		sn->dir = DOWN;
	}
	else if (PRESS(VK_RIGHT) && sn->dir != LEFT)
	{
		sn->dir = RIGHT;
	}
	else if (PRESS(VK_LEFT) && sn->dir != RIGHT)
	{
		sn->dir = LEFT;
	}
	else if (PRESS(VK_ESCAPE))
	{
		sn->state = ENDNORMAL;
	}
	else if (PRESS(VK_SPACE))
	{
		Pause();
	}
	else if (PRESS(VK_F3))
	{
		if(sn->Sleeptime>120)
		{
			sn->score += 20;
			sn->Sleeptime -= 40;
		}
	}
	else if (PRESS(VK_F5))
	{
		if (sn->state == FASTER)
		{
			sn->Sleeptime += 199;
			sn->state = OK;
		}
		if (sn->state==OK)
		{
			sn->Sleeptime -= 199;
			sn->state = FASTER;
		}
	}
	else if (PRESS(VK_F6))
	{
		if (sn->state == FASTER)
		{
			sn->Sleeptime += 199;
			sn->state = OK;
		}

	}
	else if (PRESS(VK_F4))
	{
		if (sn->Sleeptime < 260)
		{
			sn->score -= 20;
			sn->Sleeptime += 30;
		}
	}
}

void MoveSnake(pSnake sn)
{
	//设置下一个节点位置
	pSnakeNode snext = (pSnakeNode)malloc(sizeof(SnakeNode));
	snext->next = NULL;
	if (sn->dir == RIGHT)
	{
		snext->x = sn->ps->x + 2;
		snext->y = sn->ps->y;
	}
	else if (sn->dir == LEFT)
	{
		snext->x = sn->ps->x - 2;
		snext->y = sn->ps->y;
	}
	else if (sn->dir ==UP)
	{
		snext->x = sn->ps->x;
		snext->y = sn->ps->y-1;
	}
	else if (sn->dir == DOWN)
	{
		snext->x = sn->ps->x;
		snext->y = sn->ps->y+1;
	}
	//检测下一个节点是否是食物
	if ((snext->x == sn->_food->x) && (snext->y == sn->_food->y))
	{
		//吃到食物了，就把食物头插上去
		EatFood(sn,snext);
	}
	else
	{
		NormalMove(sn,snext);
	}
}
void NormalMove(pSnake sn, pSnakeNode snext)
{
	snext->next = sn->ps;
	sn->ps = snext;
	pSnakeNode cur = sn->ps;
	while (cur->next->next)
	{
		SetPos(cur->x, cur->y);
		wprintf(L"%lc", L'●');
		cur = cur->next;
	}
	SetPos(cur->next->x, cur->next->y);
	printf("  ");
	free(cur->next);//最后一个节点释放了
	cur->next = NULL;//让最后一个节点的下一个节点置空
}
void EatFood(pSnake sn,pSnakeNode snext)
{
	sn->_food->next = sn->ps;
	sn->ps = sn->_food;
	sn->score += sn->Foodscore;
	pSnakeNode cur = sn->ps;
	while (cur)
	{
		SetPos(cur->x, cur->y);
		wprintf(L"%lc", L'●');
		cur = cur->next;
	}
	printf("  ");
	free(snext);
	snext = NULL;
	CreatFood(sn);//每吃掉一个食物就再创建一个食物，让食物创建与销毁循环起来
}
void KILL_byself(pSnake sn)
{
	pSnakeNode cur = sn->ps->next->next->next;//多往后走两个cur少点判断省点时间
	while (cur)
	{
		if (cur->x == sn->ps->x && cur->y == sn->ps->y)
		{
			sn->state = Kill_Byself;
			break;
		}
		cur = cur->next;
	}
}
void KILL_bywall(pSnake sn)
{
	pSnakeNode cur = sn->ps;
	if (sn->ps->x == 112 || sn->ps->x == 0 || sn->ps->y == 52 || sn->ps->y == 0)
	{
		sn->state = Kill_By_Wall;
	}
}
void GameRun(pSnake sn)
{
	words();
	do
	{
		if (sn->state == FASTER)
		{
			sn->score += 0.1;
		}
		//打印分数
		SetPos(136, 15);
		printf("%.1f", sn->score);
		SetPos(155, 15);
		printf("%d",sn->Foodscore);
		SetPos(133, 50);
		//获取按键情况
		KEY_PRESS(sn);
		Sleep(sn->Sleeptime);
		//移动蛇蛇
		MoveSnake(sn);
		//判断是否撞墙和撞到自己
		KILL_byself(sn);
		KILL_bywall(sn);
	} while (sn->state == OK|| sn->state == FASTER);
}
void GameEnd(pSnake sn)
{
	SetPos(130, 33);
	if (sn->state == Kill_Byself)
	{
		printf("游戏结束，您不小心撞上了自己！\n");
	}
	else if (sn->state == Kill_By_Wall)
	{
		printf("游戏结束，您不小心撞上了墙！\n");
	}
	else if (sn->state == ENDNORMAL)
	{
		printf("游戏结束\n");
	}
	pSnakeNode cur = sn->ps;
	while (cur->next)
	{
		pSnakeNode pcur = cur;
		cur = cur->next;
		free(pcur);
		pcur = NULL;
	}
	free(cur);
	cur = NULL;
	SetPos(130, 35);
}